package com.bilifuture.statemachine.machine;

import com.bilifuture.statemachine.enums.StateMachineEvent;
import com.bilifuture.statemachine.enums.StateMachineType;
import com.bilifuture.statemachine.exception.StateMachineException;
import com.bilifuture.statemachine.interceptor.StateMachineInterceptor;
import com.bilifuture.statemachine.message.Message;
import com.bilifuture.statemachine.message.Response;
import com.bilifuture.statemachine.support.StateMachineConstant;
import com.bilifuture.statemachine.transition.Transition;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * @author bilifuture
 * @description: 加载所有配置好的状态机数据
 * @date 2022-02-23
 */
@Slf4j
public class StateMachine implements ApplicationContextAware, InitializingBean{
    
    /**
     * 配置文件位置
     */
    private String configLocation;
    
    /**
     * 应用程序上下文
     */
    private ApplicationContext applicationContext;
    
    /**
     * 状态机配置
     */
    private final StateMachineHolder stateMachineHolder = new StateMachineHolder();
    
    public StateMachine(String configLocation) {
        this.configLocation = configLocation;
    }
    
    /**
     * 触发状态转移
     *
     * @param stateMachine 状态机
     * @param event            事件
     * @param reqMessage       请求消息
     * @return {@link Response}
     */
    public Response trigger(StateMachineType stateMachine, StateMachineEvent event, Message reqMessage){
        //1、构建状态机上下文
        StateMachineContext context = buildStateMachineContext(stateMachine,event,reqMessage);
        
        //2、执行全局拦截器pre
        doInterceptor(context, StateMachineConstant.INTERCEPTOR_GLOBAL_PRE);
        
        //3、执行状态机级别pre
        doInterceptor(context,StateMachineConstant.INTERCEPTOR_STATEMACHINE_PRE);
        
        //4、执行Transition级别拦截器pre
        doInterceptor(context,StateMachineConstant.INTERCEPTOR_TRANSITION_PRE);
        
        //5、执行状态转移
        doTransition(context);
    
        //6、执行Transition级别拦截器post
        doInterceptor(context,StateMachineConstant.INTERCEPTOR_TRANSITION_POST);
        
        //7、执行状态机级别post
        doInterceptor(context,StateMachineConstant.INTERCEPTOR_STATEMACHINE_POST);
        
        //8、执行全局拦截器post
        doInterceptor(context, StateMachineConstant.INTERCEPTOR_GLOBAL_POST);
        
        //9、解析结果
        Response response = anaylizerContext(context);
        
        return response;
    }
    
    /**
     * 执行转移
     *
     * @param context 上下文
     */
    private void doTransition(StateMachineContext context) {
        Transition transition = context.getTransition();
        Response response = transition.transit(context);
        context.setResponse(response);
    }
    
    /**
     * 分析上下文
     *
     * @param context 上下文
     * @return {@link Response}
     */
    private Response anaylizerContext(StateMachineContext context) {
        return context.getResponse();
    }
    
    /**
     * DO拦截器
     *
     * @param context    上下文
     * @param invokeType 调用类型
     */
    private void doInterceptor(StateMachineContext context,String invokeType) {
        if(StateMachineConstant.INTERCEPTOR_GLOBAL_PRE.equals(invokeType)){
            List<StateMachineInterceptor> globalInterceptorList = this.stateMachineHolder.getGlobalInterceptorList();
            for (StateMachineInterceptor interceptor : globalInterceptorList){
                interceptor.preTransition(context);
            }
        }else if(StateMachineConstant.INTERCEPTOR_GLOBAL_POST.equals(invokeType)){
            List<StateMachineInterceptor> globalInterceptorList = this.stateMachineHolder.getGlobalInterceptorList();
            for (StateMachineInterceptor interceptor : globalInterceptorList){
                interceptor.postTransition(context);
            }
        }else if(StateMachineConstant.INTERCEPTOR_STATEMACHINE_PRE.equals(invokeType)){
            List<StateMachineInterceptor> interceptorList = context.getStateMachineConfig().getInterceptorList();
            for (StateMachineInterceptor interceptor : interceptorList){
                interceptor.preTransition(context);
            }
        }else if(StateMachineConstant.INTERCEPTOR_STATEMACHINE_POST.equals(invokeType)){
            List<StateMachineInterceptor> interceptorList = context.getStateMachineConfig().getInterceptorList();
            for (StateMachineInterceptor interceptor : interceptorList){
                interceptor.postTransition(context);
            }
        }else if(StateMachineConstant.INTERCEPTOR_TRANSITION_PRE.equals(invokeType)){
            List<StateMachineInterceptor> interceptorList = context.getTransition().getInterceptorList();
            for (StateMachineInterceptor interceptor : interceptorList){
                interceptor.preTransition(context);
            }
        }else if(StateMachineConstant.INTERCEPTOR_TRANSITION_POST.equals(invokeType)){
            List<StateMachineInterceptor> interceptorList = context.getTransition().getInterceptorList();
            for (StateMachineInterceptor interceptor : interceptorList){
                interceptor.postTransition(context);
            }
        }
    }
    
    /**
     * 构建状态机上下文
     *
     * @param stateMachine 状态机
     * @param event            事件
     * @param reqMessage       请求消息
     * @return {@link StateMachineContext}
     */
    private StateMachineContext buildStateMachineContext(StateMachineType stateMachine, StateMachineEvent event, Message reqMessage) {
        StateMachineContext context = new StateMachineContext();
        StateMachineConfig stateMachineConfig = stateMachineHolder.getStateMachineConfig(stateMachine.getStateMachineName());
        log.info("StateMachineType -> sendEvent stateMachineName:{},stateMachineConfig:{}",stateMachine.getStateMachineName(),stateMachineConfig);
        context.setStateMachineConfig(stateMachineConfig);
        context.setEvent(event.getEvent());
        context.setMessage(reqMessage);
        return context;
    }
    
    /**
     * 加载配置的状态机集合
     *
     * @throws Exception 例外情况
     */
    @Override
    public void afterPropertiesSet(){
        StateMachineBuilder builder = new StateMachineBuilder(this);
        try{
            builder.build();
        }catch (Exception e){
            log.error("StateMachineType -> 加载配置的状态机数据失败",e);
            throw new StateMachineException(e);
        }
    }
    

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    /**
     * 获取配置位置
     *
     * @return {@link String}
     */
    public String getConfigLocation() {
        return configLocation;
    }
    
    /**
     * 设置配置位置
     *
     * @param configLocation 配置位置
     */
    public void setConfigLocation(String configLocation) {
        this.configLocation = configLocation;
    }
    
    /**
     * 获取应用程序上下文
     *
     * @return {@link ApplicationContext}
     */
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    
    /**
     * 获取状态机持有器
     *
     * @return {@link StateMachineHolder}
     */
    public StateMachineHolder getStateMachineHolder() {
        return stateMachineHolder;
    }
    
}
